#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

MODULE_LICENSE("Dual BSD/GPL");
#define PROC_DIR "hello"
#define PROC_RD_FILE "rd_file" // readonly proc file

static char *file_rd_data = "This is readonly proc file"; // proc rd file 内容从此处读取

static struct proc_dir_entry *p_dir = NULL;
static struct proc_dir_entry *p_file_rd = NULL;

// seq_read 和 .open 都会调用此函数
int ProcFs_read_rd_file(struct seq_file *file, void *p)
{
	seq_printf(file, "%s\n", file_rd_data);
	return 0;
}

int ProcFs_open(struct inode *inode, struct file *file)
{
 	return single_open(file, &ProcFs_read_rd_file, NULL);
}

static struct file_operations proc_rd_name_fops = {
	.owner = THIS_MODULE,
	.open = ProcFs_open,
	.release = single_release,
	.read = seq_read,
	.llseek = seq_lseek,
};

static int hello_init(void)
{
	p_dir = proc_mkdir(PROC_DIR, NULL);
	if (!p_dir) {
		printk(KERN_ERR "Failed to create proc dir: /proc/%s\n", PROC_DIR);
		return -EINVAL;
	}

	// 创建只读 proc file
	p_file_rd = proc_create_data(
		PROC_RD_FILE, S_IFREG | S_IRUGO, p_dir, &proc_rd_name_fops, NULL);

	if (!p_file_rd) {
		printk("hello_init: creat name node failed!!!\n");
		proc_remove(p_dir);
		return -EINVAL;
	} else 
		printk("hello_init: creat proc/%s/%s success\n", PROC_DIR, PROC_RD_FILE);

	printk(KERN_INFO "Success to insmod hello.ko\n");
	return 0;
}

static void hello_exit(void)
{
	// proc_remove(p_file_rd);
	proc_remove(p_dir);
	printk(KERN_INFO "hello_exit: Success to rm proc/%s success\n", PROC_DIR);
	printk(KERN_INFO "Success to rmmod hello.ko\n");
}

module_init(hello_init);
module_exit(hello_exit);
